
package utserver;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import sun.misc.Signal;
import sun.misc.SignalHandler;

public class UTServer {

    // <editor-fold desc="sabitler"> 
    final String OK ="0";
    final String ERROR = "1";
    final String REGISTER = "2";
    final String UPDATE = "3";
    final String DELETE ="4";
    final String CHECK ="5";
    final String CHECK_ANDO = "6";
    final String POSITION = "7";
    final String MESSAGE = "8";
    final String PING_ANDO = "9";
    final String CLOSED_ANDO ="A";
    final String CHECK_T ="B";
    final String PING_T = "C";
    final String CLOSED_T = "D";
    // </editor-fold>
        
    protected HashMap<String, User> arrayUser = new HashMap<String, User>();
    //protected HashMap<String, User> arrayLoginUser = new HashMap<String, User>();
    final static Logger logger = Logger.getLogger(UTServer.class.getName());
    anaDongu dongu = new anaDongu();
    //klavyeOku oku = new klavyeOku(System.in);
        
    public static void main(String[] args) {        
        UTServer ser = new UTServer();                
    }
    
    public UTServer() {
        logger.info("0000 Program Basladi");
        try{
            logger.addHandler( new FileHandler(UTServer.class.getName() +".xml"));
        }
        catch(IOException ex){
            System.out.println("Hata logger:" + ex.toString());
        }
        
        DosyadanUserYukle();      
        
        dongu.start();
        //oku.start();
        
        try {
            Signal.handle(new Signal("TERM"), new SignalHandler() {
            // Signal handler method for CTRL-C and simple kill command.
            public void handle(Signal signal) {
                logger.warning("CTRL-C geldi. Kapanacak.");
                closeUTServer();
            }
            });
        }
        catch (final IllegalArgumentException e) {
            logger.severe("0001" + e.toString());
        }
        
        try {
            Signal.handle(new Signal("INT"), new SignalHandler() {
            // Signal handler method for kill -INT command
                @Override
            public void handle(Signal signal) {
                logger.warning("INT geldi. Kapanacak.");
                closeUTServer();
            }
            });
        }
        catch (final IllegalArgumentException e) {
            logger.severe("0002" + e.toString());
        }
        
        try {
            Signal.handle(new Signal("HUP"), new SignalHandler() {
            // Signal handler method for kill -HUP command
                @Override
            public void handle(Signal signal) {
                logger.warning("HUP geldi. Kapanacak.");
                closeUTServer();
            }
            });
        }
        catch (final IllegalArgumentException e) {
            logger.severe("0003" + e.toString());
        }        
    }
    
    public void closeUTServer(){
        dongu.closeSockets();
        try{
            dongu.stop();      
        }
        catch(Exception ex){
            logger.warning("0006" + ex.toString());
        }
        DosyayaUserKaydet();
        
        logger.info("ZZZZ Program Sonlandi");
    }
    
    //String filepath="c:\\x\\dosya.txt";
    String filepath="//home//alidereli//dosya.txt";
    private void DosyadanUserYukle(){
        
        logger.info("0028 Dosyada Kullanıcı yukleniyor");
        try{
            
            FileInputStream fstream = new FileInputStream(filepath);
            
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;
            String[] dizi;
            
            while ((strLine = br.readLine()) != null)   {
                
                strLine = strLine.replaceAll("(\\r|\\n)", "");
                
                dizi = strLine.split(";");                
                
                if( dizi.length < 5)
                    continue;
                
                User us= new User();
                us.setName(dizi[0]);
                us.setPasswd(dizi[1]);
                us.setTPasswd(dizi[2]);
                us.setMessage(dizi[3]);
                us.setisLoginAndo(false);
                us.setUyelikTarih( Long.parseLong(dizi[4]) );                
                arrayUser.put(us.getName(), us);        
                
            }            
            in.close();   
        
        }
        catch (Exception e){
            logger.warning("0028" + e.toString());
        }
                
    }
    
    private void DosyayaUserKaydet(){
        logger.info("0029 Kullanıcılar dosyaya yaziliyor");
        
        Iterator<User> dizi = arrayUser.values().iterator();
        if(!dizi.hasNext())
            return;
        
        try{
                        
            FileWriter fstream = new FileWriter(filepath);
            BufferedWriter out = new BufferedWriter(fstream);
            
            String satir ="";
            while(dizi.hasNext()) {
                User us = dizi.next();                
                satir += us.getName() +";"+us.getPasswd() +";" + us.getTPasswd() +";"+us.getMessage() +";"+ us.getUyelikTarih() +"\n";
            }
            
            out.write(satir );            
            out.close();
        }
        catch (Exception e){
            logger.warning("0029 " + e.toString());
        }
    }
    
    protected User isUser(String username){    
        
        User user= null;
        synchronized(arrayUser){            
            user = arrayUser.get(username);
        }
        return user;
    }
    
    protected void newUser(User yeniuser, InetAddress adres, int port){   
        
        byte[] sendData = new byte[1024];
        String veri="";
        try{
        
            User user = isUser(yeniuser.getName());
            if(user != null){
                veri = ERROR;
            }
            else{
                Date now = new Date();
                yeniuser.setUyelikTarih( now.getTime() );

                synchronized(arrayUser){
                    if( arrayUser.put( yeniuser.getName(), yeniuser) != null)
                        veri = OK;
                    else
                        veri = ERROR;                
                }
            }           
        }
        catch(Exception ex){
            logger.warning("0031 " + ex.toString());
            veri = ERROR;
        }
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);
        
    }
    
    protected void updateUser(User yeniuser, InetAddress adres, int port, String newpasswd, String newtpasswd){        
        
        byte[] sendData = new byte[1024];
        String veri="";
        User user = isUser(yeniuser.getName());
        if(user != null){
            veri = ERROR;
        }
        else if(!user.getPasswd().equals(yeniuser.getPasswd())){
            veri = ERROR;
        }
        else{
            synchronized(arrayUser){
                user.setPasswd(newpasswd);
                user.setTPasswd(newtpasswd);
            }
            veri = OK;
        }
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);
    }
    
    protected void delUser(User yeniuser, InetAddress adres, int port){ 
        byte[] sendData = new byte[1024];
        String veri="";
        User user = isUser(yeniuser.getName());
        if(user != null){
            veri = ERROR;
        }
        else if(!user.getPasswd().equals(yeniuser.getPasswd())){
            veri = ERROR;
        }
        else{
            synchronized(arrayUser){
                if( arrayUser.remove( yeniuser.getName() ) != null)
                    veri = OK;
                else
                    veri = ERROR;
            }
        }        
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);
    }
    
    protected void loginUser(User yeniuser, InetAddress adres, int port, boolean ando){ 
        byte[] sendData = new byte[1024];
        String veri="";
        User user = isUser(yeniuser.getName());
        if(user != null)
            veri = ERROR;        
        else if(user.getPasswd().equals(yeniuser.getPasswd()))
            veri = OK;
        else
            veri = ERROR;
        
        // androidden login olundu ise POSITION bekler hale gelmeli.
        if(veri.equals(OK) && ando){
            
            synchronized(arrayUser){          
                // daha önceden bir login olup olmadigi
                // varsa ping time suresai kontrol edilmeli.
                user.setIPAdres(adres);
                user.setPort(port);
                Date now = new Date();
                user.setPingTime(now.getTime());
                user.setisLoginAndo(true);
                
            }
        }
        
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);        
    }
    
    protected void loginUserT(User yeniuser, InetAddress adres, int port){ 
        byte[] sendData = new byte[1024];
        String veri="";
        User user = isUser(yeniuser.getName());
        if(user != null)
            veri = ERROR;        
        else if(user.getTPasswd().equals(yeniuser.getTPasswd()))
            veri = OK;
        else
            veri = ERROR;
        
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);        
    }
    
    protected void sendPosition(User us,  InetAddress adres, int port){
        byte[] sendData = new byte[1024];
        String veri="";
        
        if(us.getPositionX() < 0 || us.getPositionY() <0){
            veri = ERROR;
            logger.warning("0017 x yada y degeri negatif " + us.getName() +"--" + adres.toString()  );
            //karaliste
        }
        else{
            User user = isUser(us.getName());
            
            if(checkUser(user, us, adres)){
                veri = OK;
                Iterator<String> izleyiciler;
            synchronized(arrayUser){                            
                user.setPositionX( us.getPositionX() );
                user.setPositionY( us.getPositionY() );
                Date now = new Date();
                user.setPingTime(now.getTime());
                izleyiciler = user.getIzleyici();
            }
            
            if(izleyiciler != null && !izleyiciler.hasNext()){
                sendPositionIzleyici(us.getPositionX(), us.getPositionY(), izleyiciler);
            }
            }
            else{
                veri = ERROR;                
            }           
                        
        }
        
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);  
    }
    
    private void sendPositionIzleyici(long x, long y, Iterator<String> izleyiciler) {
        byte[] sendData = new byte[1024];
        String veri= POSITION;
        sendData = (veri +";"+x+";"+y +"\n").getBytes();
        
        InetAddress adres;
        int port;
        
        String[] parse;
        while(izleyiciler.hasNext()) {
            parse = izleyiciler.next().split(";");
            
            if(parse.length == 2)
                continue;
            try{
                adres =InetAddress.getByName(parse[0]);
                port = Integer.getInteger(parse[1]);
                
                DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
                dongu.sendData(cevappaketi); 
            }
            catch(Exception ex){
                logger.warning("0018 " + parse[0] +"--" + parse[1] + ex  );
            }
        }       
    }
    
    protected void sendMessage(User us,  InetAddress adres, int port){
        byte[] sendData = new byte[1024];
        String veri="";
        
        
        User user = isUser(us.getName());
            
        if(checkUser(user, us, adres)){
            veri = OK;
            Iterator<String> izleyiciler;
            synchronized(arrayUser){                            
                user.setMessage(us.getMessage());
                Date now = new Date();
                user.setPingTime(now.getTime());
                izleyiciler = user.getIzleyici();
            }

            if(izleyiciler != null && !izleyiciler.hasNext()){
                sendMessageIzleyici(us.getMessage(), izleyiciler);
            }
        }
        else{
            veri = ERROR;
        }                                  
                
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);  
    }
    
    private void sendMessageIzleyici(String mesaj, Iterator<String> izleyiciler) {
        byte[] sendData = new byte[1024];
        String veri= MESSAGE;
        sendData = (veri +";"+ mesaj +"\n").getBytes();
        
        InetAddress adres;
        int port;
        
        String[] parse;
        while(izleyiciler.hasNext()) {
            parse = izleyiciler.next().split(";");
            
            if(parse.length == 2)
                continue;
            try{
                adres =InetAddress.getByName(parse[0]);
                port = Integer.getInteger(parse[1]);
                
                DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
                dongu.sendData(cevappaketi); 
            }
            catch(Exception ex){
                logger.warning("0022  " + parse[0] +"--" + parse[1] +ex.toString()  );
            }
        }       
    }
    
    protected void pingAndo(User us,  InetAddress adres, int port){
        byte[] sendData = new byte[1024];
        String veri="";
        
        User user = isUser(us.getName());            
        if(checkUser(user, us, adres)){
            veri = OK;            
            synchronized(arrayUser){                            
                Date now = new Date();
                user.setPingTime(now.getTime());
            }
        }
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);  
    }
    
    protected void closeAndo(User us,  InetAddress adres, int port){
        byte[] sendData = new byte[1024];
        String veri="";
        
        User user = isUser(us.getName());            
        if(checkUser(user, us, adres)){
            veri = OK;
            Iterator<String> izleyiciler;
            synchronized(arrayUser){                            
                user.setisLoginAndo(false);
                izleyiciler = user.getIzleyici();
                user.removeIzleyiciAll(); 
            }
            
            if(izleyiciler != null && !izleyiciler.hasNext()){
                closeAndoIzleyici(izleyiciler, us.getName());                
            }
        }
        sendData = (veri +"\n").getBytes();        
        DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
        
        dongu.sendData(cevappaketi);  
    }
    
    private void closeAndoIzleyici(Iterator<String> izleyiciler, String username) {
        byte[] sendData = new byte[1024];
        String veri= CLOSED_ANDO;
        sendData = (veri+";"+ username +"\n").getBytes();
        
        InetAddress adres;
        int port;
        
        String[] parse;
        while(izleyiciler.hasNext()) {
            parse = izleyiciler.next().split(";");
            
            if(parse.length == 2)
                continue;
            try{
                adres =InetAddress.getByName(parse[0]);
                port = Integer.getInteger(parse[1]);
                
                DatagramPacket cevappaketi = new DatagramPacket(sendData, sendData.length, adres, port);
                dongu.sendData(cevappaketi); 
            }
            catch(Exception ex){
                logger.warning("0024  " + parse[0] +"--" + parse[1] +ex.toString()  );
            }
        }       
    }
    
    protected void closeIzleyen(User us,  InetAddress adres, int port){
                        
        User user = isUser(us.getName());            
        if(checkUserT(user, us, adres)){                        
            synchronized(arrayUser){                            
                user.removeIzleyici(adres, port); 
            }            
        }        
    }
    
    protected void checkArraysforPingTime(){        
        synchronized(arrayUser){
            
        }
    }
    
    private boolean checkUser(User kayitli, User gelen, InetAddress adres){
        
        boolean donecek = true;
        if(kayitli != null){
            donecek = false;
            logger.warning("0021 position var user yok " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getPasswd().equals(gelen.getPasswd())){
            donecek = false;
            logger.warning("0021 position var sifre tutmuyor " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getisLoginAndo()){
            donecek = false;
            logger.warning("0021 position var login degil " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getIPAdres().toString().equals(gelen.getIPAdres().toString())){
            donecek = false;
            logger.warning("0021 position var login degil " + gelen.getName() +"--" + adres.toString()  );
        }
                
        return donecek;
    }
    
    private boolean checkUserT(User kayitli, User gelen, InetAddress adres){
        
        boolean donecek = true;
        if(kayitli != null){
            donecek = false;
            logger.warning("0028 position var user yok " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getTPasswd().equals(gelen.getTPasswd())){
            donecek = false;
            logger.warning("0028 position var tsifre tutmuyor " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getisLoginAndo()){
            donecek = false;
            logger.warning("0028 position var login degil " + gelen.getName() +"--" + adres.toString()  );
        }
        else if( !kayitli.getIPAdres().toString().equals(gelen.getIPAdres().toString())){
            donecek = false;
            logger.warning("0028 position var login degil " + gelen.getName() +"--" + adres.toString()  );
        }
                
        return donecek;
    }
    
/*
* CLASS BASLANGICI
*/

public class anaDongu extends Thread{
            
    
    DatagramSocket socket;
    //SocketAddress adres;
    DatagramSocket clientSocket; 
    Boolean dongudevam = true;
       
    public void run(){
            
        //DatagramPacket packet;
        try {
                
            clientSocket = new DatagramSocket();
            socket = new DatagramSocket(11572);
            //socket.setSoTimeout(beklemesuresi);

            byte [] buffer = new byte[1024]; 
            while(dongudevam){
                try{

                    DatagramPacket gelenpacket = new DatagramPacket(buffer, buffer.length);
                    //gelenpacket.setAddress(null);
                    //gelenpacket.setPort(MIN_PRIORITY);
                    socket.receive(gelenpacket);
                    paketParcala(gelenpacket);   
                    
                }
                catch(java.net.SocketTimeoutException exsoc){
                    logger.warning("0007" + exsoc.toString());    
                }   
            }
        }
        catch(IOException e)    
        {
            //System.out.println("Soketde Hata:"+ e +"\n" );
            logger.warning("0008" + e.toString());
        }   
    
    }    
    
    public void paketParcala(DatagramPacket gelenpacket){
         
        String veri= new String(gelenpacket.getData());        
        veri = veri.substring(0, veri.indexOf('\n') ); 
        veri = veri.trim();    
        
        logger.info("0011 a veri" + veri);
        
        String[] parcalanmisdata = veri.split(",");
        
        String komut="";
        if(parcalanmisdata.length > 0)
            komut = parcalanmisdata[0];
        else
            return;
        
        
        //int sayac=0;
                  
        if( komut.equals(REGISTER)){

            //sadece belirli IP den gelebilir.                
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]
            //tpasswd parcalanmisdata[3]

            if(parcalanmisdata.length == 4){
                User user = new User();
                user.setName(parcalanmisdata[1]);
                user.setPasswd(parcalanmisdata[2]);
                user.setTPasswd(parcalanmisdata[3]);
                user.setMessage("*");

                newUser(user, gelenpacket.getAddress(), gelenpacket.getPort());
            }
            else{
                logger.info("0011 a boyut yetersiz" + parcalanmisdata.length);
            }

        }
        /*
        else if( komut.equals(UPDATE) ){
            //sadece belirli IP den gelebilir.
            // login
            // passwd 
            // newpasswd
            // newtpasswd

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);
            String newpasswd = parcalanmisdata[3];
            String newtpasswd = parcalanmisdata[4];
            logger.info("0012" + "update " + user.getName());
            updateUser(user, gelenpacket.getAddress(), gelenpacket.getPort(), newpasswd, newtpasswd);

        }
        else if( komut.equals(DELETE) ){
            //sadece belirli IP den gelebilir.
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);
            logger.info("0013" + "delete " + user.getName());                
            delUser(user, gelenpacket.getAddress(), gelenpacket.getPort());

        }
        else if( komut.equals(CHECK) || komut.equals(CHECK_ANDO) ){
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);
            logger.info("0014" + "check - check_ando " + user.getName());
            boolean android = false;
            if(komut.equals(CHECK_ANDO))
                android = true;
            loginUser(user, gelenpacket.getAddress(), gelenpacket.getPort(), android);
        }
        else if( komut.equals(CHECK_T) ){
            //login, parcalanmisdata[1]
            //passwdt, parcalanmisdata[2]

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setTPasswd(parcalanmisdata[2]);

            logger.info("0015" + "checkT" + user.getName());
            loginUserT(user, gelenpacket.getAddress(), gelenpacket.getPort());
        }
        else if( komut.equals(POSITION) ){
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]
            //x
            //y
            long x =0;
            long y =0;
            try{
                x = Long.parseLong(parcalanmisdata[3]);
                y = Long.parseLong(parcalanmisdata[4]);
            }
            catch(NumberFormatException nuex){
                logger.warning("0016" + nuex.toString());
                x = -1;
                y = -1;
            }

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);
            user.setPositionX(x );
            user.setPositionY(y );

            logger.info("0019" + "position" + user.getName());
            sendPosition(user,gelenpacket.getAddress(), gelenpacket.getPort());
        }
        else if( komut.equals(MESSAGE) ){
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]
            // message

            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);
            user.setMessage(parcalanmisdata[3]);

            logger.info("0020" + "MESSAGE" + user.getName());
            sendPosition(user,gelenpacket.getAddress(), gelenpacket.getPort());
        }
        else if( komut.equals(PING_ANDO)){
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]                                                 
            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);                                
            logger.info("0023" + "PING_ANDO" + user.getName());
            pingAndo(user,gelenpacket.getAddress(), gelenpacket.getPort());            
        }
        else if( komut.equals(CLOSED_ANDO)){
            //login, parcalanmisdata[1]
            //passwd, parcalanmisdata[2]                                                 
            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setPasswd(parcalanmisdata[2]);                                
            logger.info("0026" + "CLOSED_ANDO" + user.getName());
            closeAndo(user,gelenpacket.getAddress(), gelenpacket.getPort());            
        }
        else if( komut.equals(CLOSED_T)){
            //login, parcalanmisdata[1]
            //passwdt, parcalanmisdata[2]                                                 
            User user = new User();
            user.setName(parcalanmisdata[1]);
            user.setTPasswd(parcalanmisdata[2]);                                
            logger.info("0027" + "CLOSED_T" + user.getName());
            closeIzleyen(user,gelenpacket.getAddress(), gelenpacket.getPort());                           
        }
        // PING_T simdilik kullanilmayacak
        */
             
        
    }
    
    public void sendData(DatagramPacket sendPacket){ 
		  
	try{
            clientSocket.send(sendPacket);
	}
	catch (Exception e) { 
	    logger.warning("0010" + e.toString());	
        }
        
        logger.info("0010 Paket Gonderildi: " + sendPacket.getPort() );
        
    }
    
    public void closeSockets(){
        dongudevam = false;
        try{
            if( !socket.isClosed() ){
                socket.close();
                logger.info("0004 soket kapatildi.");
                
            }
	}
	catch (Exception e) {
            logger.warning("0004" + e.toString());
        }
        
        try{
            if( !clientSocket.isClosed() ){
                clientSocket.close();
                logger.info("0005 client soket kapatildi.");
                
            }
        }
	catch (Exception e) { 
	    logger.warning("0005" + e.toString());	
        }
        
        
    }
}    


/*
*  2 CLASS BASLANGICI
*/

    
}


